package com.lemon.exam.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA加解密工具类，这是单例的工具类
 *
 * @author Lemon
 * @since 2024/5/24 9:27
 */
@Slf4j
public class RsaUtil {
    //加密算法RSA
    private static final String KEY_ALGORITHM = "RSA";

    private static final Object object = new Object();

    private static volatile RsaUtil instance;

    private RsaUtil() {
    }

    public static RsaUtil getInstance() {
        if (instance == null) {
            synchronized (object) {
                if (instance == null) {
                    instance = new RsaUtil();
                }
            }
        }
        return instance;
    }

    /**
     * 公钥解密
     *
     * @param publicKey 公钥
     * @param text      待解密的信息
     * @return 解密后的数据
     */
    public String decryptByPublicKey(String publicKey, String text) {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey key = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] result = cipher.doFinal(Base64.decodeBase64(text));
            return new String(result);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | NoSuchPaddingException |
                 IllegalBlockSizeException | BadPaddingException e) {
            log.error("RsaUtil.decryptByPublicKey.message:{}", e.getMessage());
            return null;
        }

    }

    /**
     * 私钥加密
     *
     * @param privateKey 私钥
     * @param text       待加密的信息
     * @return 加密后的字符串
     */
    public String encryptByPrivateKey(String privateKey, String text) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey key = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(text.getBytes());
            return Base64.encodeBase64String(result);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | NoSuchPaddingException |
                 IllegalBlockSizeException | BadPaddingException e) {
            log.error("RsaUtil.encryptByPrivateKey.message:{}", e.getMessage());
            return null;
        }
    }

    /**
     * 私钥解密
     *
     * @param privateKey 私钥
     * @param text       待解密的文本
     * @return 解密后的字符串
     */
    public String decryptByPrivateKey(String privateKey, String text) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey key = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] result = cipher.doFinal(Base64.decodeBase64(text));
            return new String(result);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | NoSuchPaddingException |
                 IllegalBlockSizeException | BadPaddingException e) {
            log.error("RsaUtil.decryptByPrivateKey.message:{}", e.getMessage());
            return null;
        }

    }

    /**
     * 公钥加密
     *
     * @param publicKey 公钥
     * @param text      待加密的文本
     * @return 加密后的数据
     */
    public String encryptByPublicKey(String publicKey, String text) {
        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey key = keyFactory.generatePublic(x509EncodedKeySpec2);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] result = cipher.doFinal(text.getBytes());
            return Base64.encodeBase64String(result);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | NoSuchPaddingException |
                 IllegalBlockSizeException | BadPaddingException e) {
            log.error("RsaUtil.encryptByPublicKey.message:{}", e.getMessage());
            return null;
        }
    }

    /**
     * 生成公钥和私钥
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(1024);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            String publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
            String privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
            System.out.println("公钥：" + publicKey);
            System.out.println("私钥：" + privateKey);
        } catch (NoSuchAlgorithmException e) {
            log.error("生成密钥对失败，message:{}", e.getMessage());
        }
    }
}
